1 /**
2  * Templates for container node types.
3  * Copyright: © 2015 Economic Modeling Specialists, Intl.
4  * Authors: Brian Schott
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
6  */
7 module containers.internal.node;
8 
9 template FatNodeInfo(size_t bytesPerItem, size_t pointerCount, size_t cacheLineSize = 64,
10 	size_t extraSpace = size_t.max)
11 {
12 	import std.meta : AliasSeq;
13 	import std.format : format;
14 	template fatNodeCapacity(alias L, bool CheckLength = true)
15 	{
16 		enum size_t optimistic = (cacheLineSize
17 			- ((void*).sizeof * pointerCount) - L) / bytesPerItem;
18 		static if (optimistic > 0)
19 		{
20 			enum fatNodeCapacity = optimistic;
21 			static if (CheckLength)
22 			{
23 				static assert(optimistic <= L * 8, ("%d bits required for bookkeeping"
24 					~ " but only %d are possible. Try reducing the cache line size argument.")
25 					.format(optimistic, L * 8));
26 			}
27 		}
28 		else
29 			enum fatNodeCapacity = 1;
30 	}
31 	static if (extraSpace == size_t.max)
32 	{
33 		static if (__traits(compiles, fatNodeCapacity!(ubyte.sizeof)))
34 			alias FatNodeInfo = AliasSeq!(fatNodeCapacity!(ubyte.sizeof), ubyte);
35 		else static if (__traits(compiles, fatNodeCapacity!(ushort.sizeof)))
36 			alias FatNodeInfo = AliasSeq!(fatNodeCapacity!(ushort.sizeof), ushort);
37 		else static if (__traits(compiles, fatNodeCapacity!(uint.sizeof)))
38 			alias FatNodeInfo = AliasSeq!(fatNodeCapacity!(uint.sizeof), uint);
39 		else static if (__traits(compiles, fatNodeCapacity!(ulong.sizeof)))
40 			alias FatNodeInfo = AliasSeq!(fatNodeCapacity!(ulong.sizeof), ulong);
41 		else static assert(false, "No type big enough to store " ~ extraSpace.stringof);
42 	}
43 	else
44 		alias FatNodeInfo = AliasSeq!(fatNodeCapacity!(extraSpace, false), void);
45 }
46 
47 // Double linked fat node of int with bookkeeping in a uint should be able to
48 // hold 11 ints per node.
49 // 64 - 16 - 4 = 4 * 11
50 version (X86_64)
51 	static assert (FatNodeInfo!(int.sizeof, 2)[0] == 11);
52 
53 template shouldNullSlot(T)
54 {
55 	import std.traits;
56 	enum shouldNullSlot = isPointer!T || is (T == class) || is (T == interface) || isDynamicArray!T 
57 							|| is(T == delegate); // closures or class method shoulde be null for GC recycle
58 }
59 
60 template shouldAddGCRange(T)
61 {
62 	import std.traits;
63 	enum shouldAddGCRange = hasIndirections!T;
64 }
65 
66 static assert (shouldAddGCRange!string);
67 static assert (!shouldAddGCRange!int);
68 
69 template fullBits(T, size_t n, size_t c = 0)
70 {
71 	static if (c >= (n - 1))
72 		enum T fullBits = (T(1) << c);
73 	else
74 		enum T fullBits = (T(1) << c) | fullBits!(T, n, c + 1);
75 }
76 
77 static assert (fullBits!(ushort, 1) == 1);
78 static assert (fullBits!(ushort, 2) == 3);
79 static assert (fullBits!(ushort, 3) == 7);
80 static assert (fullBits!(ushort, 4) == 15);